/*
 * RTSAI - Real-Time Strategy engine for AI research
 * Copyright(C) 2006 DIMAp-UFRN, licensed under LGPL
 *
 * Pool allocator ( Pool.cpp )
 * Author: Diogo Leite Reboucas
 */

#ifndef POOL_CPP_
#define POOL_CPP_

// INCLUDES ===================================================================
#include "Pool.h"
#include "Exceptions.h"
#include "Common.h"

// IMPLEMENTATIONS ============================================================

// PUBLIC METHODS +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// Constructor ----------------------------------------------------------------
/*! Default constructor. This constructor sets the initial capacity of the
 *  pool.
 *  @param a Initial pool capacity.
 */
template < class T >
Pool < T > :: Pool ( const int& a ) : pool ( vector<T> (a) ),
                                      st ( stack<int>() ),
                                      size (0)
{
    this->update_ids ();
}


// int ------------------------------------------------------------------------
/*! This method returns the number of entities in use.
 *  @return A number of used entities.
 */
template < class T >
int Pool < T > :: get_size ()
{
    return this->size;
}


/*! This method returns the number of entities at the pool.
 *  @return A number of entities at the pool.
 */
template < class T >
int Pool < T > :: get_pool_size ()
{
    return this->pool.size();
}


// T --------------------------------------------------------------------------
/*! This method "creates" a new entity and returns it's reference.
 *  @return A reference to the new created unit.
 */
template < class T >
T& Pool < T > :: create ()
{
    this->size++; // Updating used entities
    int index = -1;

    if ( !st.empty () ) // Have an entity at stack
    {
        index = this->st.top();
        this->st.pop ();
    }
    else // Just creates
    {
        index = size - 1;
    }

    pool[ index ].set_id ( index );

    return pool[ index ];
}

template < class T >
T& Pool < T > :: operator [] ( const int& index )
{
    if ( index < 0 || index > ( (int)pool.size () - 1 ) )
    {
        throw IndexOutOfBoundsException ( "Index out of bounds." ) ;
    }

    return pool[ index ];
}

// void -----------------------------------------------------------------------
/*! This method "destroy" an entity and put it's ID into stack.
 *  @param a To be destroyd entity.
 */
template < class T >
void Pool < T > :: destroy ( T& entity )
{
    if ( entity.get_id () < 0 || (unsigned)entity.get_id () > this->size )
        throw InvalidEntityException ("Invalid entity ID or entity does not "
                                      "exist.");

    entity.reset ();
    this->st.push ( entity.get_id () );
    entity.set_id (-1);
    this->size--;
}

/*! This method "resets" the attributes.
 */
template < class T >
void Pool < T > :: clear ()
{
    typename std::vector<T>::iterator elm = pool.begin();
    while ( elm != pool.end() )
    {
        (*elm).reset();
        ++elm;
    }
    pool.clear();

    while ( !st.empty() )
        st.pop();

    this->update_ids ();
}

// Destructor -----------------------------------------------------------------
/*! Just deletes the pool and the stack.
 */
template < class T >
Pool < T > :: ~Pool ()
{
    /* empty */
}

// PRIVATE METHODS ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// void -----------------------------------------------------------------------
/*! This method update the id's of entities at pool
 */
template < class T >
void Pool < T > :: update_ids ()
{
    for ( unsigned int i = this->size ; i < pool.capacity () ; i++ )
    {
        // pool[ i ].set_id ( i );
        pool[ i ].set_id ( -1 );
    }
}

#endif // POOL_CPP_
